package fr.uvsq.isty.bdh.hchess.interfacing;

import ictk.boardgame.History;
import ictk.boardgame.IllegalMoveException;
import ictk.boardgame.Move;
import ictk.boardgame.chess.*;
import java.util.ArrayList;

/**
 *
 * @author Clement Bellot <clementbellot@gmail.com>
 * @author Florent Hemmi <florent.hemmi@gmail.com>
 */
public class Helpers {
    public static GameEndResult getWinner(GameEvent e){
        if(e==GameEvent.WHITE_CHECKMATE) return GameEndResult.WHITE_WIN;
        if(e==GameEvent.BLACK_OUT_OF_TIME) return GameEndResult.WHITE_WIN;
        if(e==GameEvent.BLACK_BAD_MOVE) return GameEndResult.WHITE_WIN;
        if(e==GameEvent.BLACK_SURRENDERED) return GameEndResult.WHITE_WIN;
        
        if(e==GameEvent.BLACK_CHECKMATE) return GameEndResult.BLACK_WIN;
        if(e==GameEvent.WHITE_OUT_OF_TIME) return GameEndResult.BLACK_WIN;
        if(e==GameEvent.WHITE_BAD_MOVE) return GameEndResult.BLACK_WIN;
        if(e==GameEvent.WHITE_SURRENDERED) return GameEndResult.BLACK_WIN;
        
        return GameEndResult.DRAW;
    }
    
    public static ChessBoard fixedSizeUnserializeBoard(String serializedBoard){
        ChessBoard chess = new ChessBoard();
        char[][] matrix = new char[8][8];
        for (int i=0;i<ictk.boardgame.chess.ChessBoard.MAX_RANK; i++) {
            for (int j=0; j<ictk.boardgame.chess.ChessBoard.MAX_FILE; j++) {
                int nbChar = i*9 + j;
                matrix[j][i] = serializedBoard.charAt(nbChar);
            }
        }
        chess.setPosition(matrix);
        return chess;
    }
    
    public static String fixedSizeSerializeBoard(ChessBoard board){
        StringBuilder str = new StringBuilder("");
        for (int i=0; i<ictk.boardgame.chess.ChessBoard.MAX_RANK+1; i++) {
            for (int j=0; j<ictk.boardgame.chess.ChessBoard.MAX_FILE+1; j++) {
                str.append(board.toCharArray()[j][i]);
            }
        }
        assert str.length() == Helpers.getBoardSizeFixedSerialized();
        return str.toString();
    }
    
    public static String fixedSizeSerializeMove(ChessMove move){
        int[] moveAsInt = intArrayFromMove(move);
        StringBuilder str = new StringBuilder("");
        str.append(moveAsInt[0]);
        str.append(moveAsInt[1]);
        str.append(moveAsInt[2]);
        str.append(moveAsInt[3]);
        if(moveAsInt.length==4){
            str.append(" ");
        }else{
            str.append(moveAsInt[4]);
        }
        assert str.length() == Helpers.getMoveSizeFixedSerialized();
        return str.toString();
    }
    
    public static ChessMove fixedSizeUnserializeMove(ChessBoard board,String serializedBoard){
        String s = serializedBoard;
        ChessMove ret;
        int fromX, fromY, destX, destY;
        fromX = Integer.parseInt(s.substring(0,1));
        fromY = Integer.parseInt(s.substring(1,2));
        destX = Integer.parseInt(s.substring(2,3));
        destY = Integer.parseInt(s.substring(3,4));
        try{
            if (s.charAt(4) == ' ') {
                ret = new ChessMove(board, fromX, fromY, destX, destY);
            } else {
                int promotion = Integer.parseInt(s.substring(4,5));
                ret = new ChessMove(board,fromX, fromY,destX, destY, promotion);
            }
        }catch (IllegalMoveException ex){
            assert false;
            return null;
        }
        return ret;
    }
    
    public static ChessBoard copyBoard(ChessBoard board) {
        String serializedBoard = fixedSizeSerializeBoard(board);
        ChessBoard copiedBoard = fixedSizeUnserializeBoard(serializedBoard);
        return copiedBoard;
    }
    
    public static int getMoveSizeFixedSerialized(){
        return 5;
    }
    
    public static int getBoardSizeFixedSerialized(){
        return 9*9;
    }
    
    public static String uciMoveFromIntArray(int[] move){
        String ret = "";
        ret += String.valueOf((char)(move[0]+'a'-1));
        ret += String.valueOf((char)(move[1]+'1'-1));
        ret += String.valueOf((char)(move[2]+'a'-1));
        ret += String.valueOf((char)(move[3]+'1'-1));
        if(move.length==5){
            int promotion = move[4];
            if(promotion>ChessPiece.BLACK_OFFSET){
                promotion -= ChessPiece.BLACK_OFFSET;
            }
            if(promotion == Bishop.INDEX){
                ret += "b";
            }else if(promotion == Rook.INDEX){
                ret += "r";
            }else if(promotion == Knight.INDEX){
                ret += "n";
            }else if(promotion == Queen.INDEX){
                ret += "q";
            }else if(promotion == Pawn.INDEX){
                ret += "p";
                assert false : "Weird promotion you have here.";
            }else{
                assert false : "Unknown piece.";
            }
        }
        return ret;
    }
    public static int[] intArrayFromUciMove(String move){
        int[] ret = new int[move.length()];
        char[] moveAsChar = move.toCharArray();
        ret[0] = moveAsChar[0]-'a'+1;
        ret[1] = moveAsChar[1]-'1'+1;
        ret[2] = moveAsChar[2]-'a'+1;
        ret[3] = moveAsChar[3]-'1'+1;
        if(move.length()==5){
            char promo = moveAsChar[4];
            if(promo=='b'){
                ret[4] = Bishop.INDEX;
            }else if(promo=='r'){
                ret[4] = Rook.INDEX;
            }else if(promo=='n'){
                ret[4] = Knight.INDEX;
            }else if(promo=='q'){
                ret[4] = Queen.INDEX;
            }else if(promo=='p'){
                ret[4] = Pawn.INDEX;
            }else{
                assert false : "Unknown piece.";
            }
        }
        return ret;
    }
    
    public static int[] intArrayFromMove(ChessMove move){
        int[] ret;
        // Special case for castling to avoid a bug in ictk.
        if(move==null){
            assert false : "Stop sending junk.";
        }
        if(move.isCastleKingside()){
            if(move.isBlackMove()){
                return new int[]{5,8,7,8};
            }else{
                return new int[]{5,1,7,1};
            }
        }else if(move.isCastleQueenside()){
            if(move.isBlackMove()){
                return new int[]{5,8,3,8};
            }else{
                return new int[]{5,1,3,1};
            }
        }
        ChessPiece promotion = move.getPromotion();
        if (promotion == null){
            ret = new int[4];
        }else{
            ret = new int[5];
            if(promotion.getIndex()>=5){
                ret[4] = promotion.getIndex()-ChessPiece.BLACK_OFFSET;
            }else{
                ret[4] = promotion.getIndex();
            }
        }
        ret[0] = move.getOriginCoordinates()[0];
        ret[1] = move.getOriginCoordinates()[1];
        ret[2] = move.getDestinationCoordinates()[0];
        ret[3] = move.getDestinationCoordinates()[1];
        return ret;
    }
    
    public static int[][] intArrayFromCurrentHistoryPosition(History h){
        ArrayList<int[]> ret = new ArrayList<int[]>();
        Move whenToStop = h.getCurrentMove();
        Move currentMove = null;
        h.rewind();
        while(currentMove!=whenToStop){
            currentMove = h.next();
            ret.add(intArrayFromMove((ChessMove)currentMove));
        }
        int[][] retInt = new int[ret.size()][];
        for (int i=0; i<ret.size(); i++) {
            retInt[i] = ret.get(i);
        }
        return retInt;
    }
}
